using System;
using System.Collections.Generic;
using System.Reflection;
using System.ServiceProcess;
using System.Xml.XPath;

namespace SharpService.Container
{
    public class Program
    {
        public static void Main(string[] args)
        {
            XPathDocument doc = new XPathDocument(args[0]);
            XPathNavigator nav = doc.CreateNavigator();
            List<ServiceBase> services = ParseServices(nav);
            if (services.Count > 0)
            {
                XPathNavigator dirNav = nav.SelectSingleNode("//dir");
                string dir = null;
                if (dirNav != null)
                {
                    dir = dirNav.Value;
                }

                if (dir != null)
                {
                    System.IO.Directory.SetCurrentDirectory(dir);
                }
            }
            ServiceBase.Run(services.ToArray());
        }

        public static List<ServiceBase> ParseServices(XPathNavigator nav)
        {
            XPathNodeIterator services = nav.Select("//service");
            List<ServiceBase> allServices = new List<ServiceBase>();
            while (services.MoveNext())
            {
                ServiceBase serv = CreateService(services.Current);
                allServices.Add(serv);
            }
            return allServices;
        }

        public static ServiceBase CreateService(XPathNavigator xPathNavigator)
        {
            string classType = xPathNavigator.GetAttribute("type", "");
            Type serviceType = Type.GetType(classType);
            if (serviceType == null)
            {
                throw new Exception("Unable to resolve type: " + classType);
            }
            ConstructorInfo info = serviceType.GetConstructor(new Type[] {typeof (string[])});
            if (info != null)
            {
                List<string> args = new List<string>();

                XPathNodeIterator nodeIterator = xPathNavigator.SelectDescendants("arg", "", false);
                while (nodeIterator.MoveNext())
                {
                    args.Add(nodeIterator.Current.Value);
                }
                return (ServiceBase) info.Invoke(new object[] {args.ToArray()});
            }
            return (ServiceBase) serviceType.GetConstructor(new Type[0]).Invoke(new object[0]);
        }
    }
}